#include "../include/terrain.hpp"
#include <stdlib.h>
#include <limits.h>
#include <time.h>
using namespace std;

void Terrain::calcul()
{
    string use;
    bool premier_pass = true;
    bool ok;
    unsigned int i=0;
    //au début vider les parcelles
    ligneCourante = new int[lecteur->getNbCol()];
    ecriture = new int[lecteur->getNbCol()];
    lesParcelles_up= new Parcelle[lecteur->getNbCol()];
    lesParcelles_center = new Parcelle[lecteur->getNbCol()];
    lesParcelles_down = new Parcelle[lecteur->getNbCol()];
    lesParcelles_downdown = new Parcelle[lecteur->getNbCol()];
    Parcelle * aux;
    lignes_traitees=0;
    clock_t start, end;
    double elapsed;
    start = clock();
    //tant que on a pas fini le fichier
    while(lignes_traitees < lecteur->getNbLig())
    {
        //vider les parcelles mais pas la dernière ligne
            /*if(lignes_traitees%40 == 0)
            {
                cout<<"ligne "<<lignes_traitees<<endl;
                end = clock();
                elapsed = ((double)end - start) / CLOCKS_PER_SEC;
                cout <<"time : "<< elapsed<<"  "<<Box::cpt<< endl;
                start = clock(); Box::cpt=0;
            }*/


        if (!premier_pass)
        {
            //déja des lignes, on charge la dernière
            if (lesParcelles_up != NULL)
            {
                delete [] lesParcelles_up;
                lesParcelles_up = lesParcelles_center;
                lesParcelles_center = lesParcelles_down;
                lesParcelles_down= lesParcelles_downdown;

            }
            //on charge deux lignes de plus

            ok=lecteur->getNextLine(ligneCourante);
            aux = new Parcelle[lecteur->getNbCol()];
            lesParcelles_downdown = aux;
            for (unsigned int itzz = 0; itzz < lecteur->getNbCol(); itzz++)
            {
                //pour tout int de ligneCourante creer une parcelle
                lesParcelles_downdown[itzz] = Parcelle(ligneCourante[itzz],itzz,lignes_traitees);
            }
            //on a traité un ligne donc ligne traitees++
            lignes_traitees++;

            for (i=0; i< lecteur->getNbCol() ; i++)
            {
                if(lesParcelles_center[i].getNumBassin() == -1)
                {
                    calculCuvette(&lesParcelles_center[i]);
                }
                else if(calculCible(&lesParcelles_center[i])->getNumBassin() != lesParcelles_center[i].getNumBassin())
                {
                    Parcelle * troll = calculCible(&lesParcelles_center[i]);
                    int cpt = 0;
                    while(troll->getNumBassin() == -1 && cpt < 3)
                    {
                        troll = calculCible(troll);
                        cpt++;

                    }
                    MAJBassin[lesParcelles_center[i].getNumBassin()] = troll->getNumBassin();
                }
            }

            //un fois le calcul fais, on rajoute une line au lecteur pour ecrire le resultas
            for(unsigned int e0 = 0 ; e0 < lecteur->getNbCol(); e0++)
            {
                ecriture[e0]=lesParcelles_center[e0].getNumBassin();
            }
            lecteur->addLine(ecriture);
            jucpt++;
        }
        else
        {
            //premier passage effectué
            premier_pass = false;
            //Les parcelles vides, remplir avec les trois premières lignes
            //premiere ligne
            ok=lecteur->getNextLine(ligneCourante);
            for (unsigned int itlig=0; itlig< lecteur->getNbCol(); itlig++)
            {
                //pour tout int de ligneCourante creer une parcelle
                lesParcelles_up[itlig] = Parcelle(ligneCourante[itlig],itlig,lignes_traitees);

            }
            //on a traité un ligne donc ligne traitees++
            lignes_traitees++;
            //seconde ligne
            ok=lecteur->getNextLine(ligneCourante);
            for (unsigned int itligg=0; itligg< lecteur->getNbCol(); itligg++)
            {
                lesParcelles_center[itligg] = Parcelle(ligneCourante[itligg],itligg,lignes_traitees);

            }
            //on a traité un ligne donc ligne traitees++
            lignes_traitees++;
            //troisieme ligne
            ok=lecteur->getNextLine(ligneCourante);
            for (unsigned int itliggg=0; itliggg< lecteur->getNbCol(); itliggg++)
            {
                lesParcelles_down[itliggg] = Parcelle(ligneCourante[itliggg],itliggg,lignes_traitees);
            }
            lignes_traitees++;

            ok=lecteur->getNextLine(ligneCourante);
            for(unsigned int itligggg=0 ; itligggg < lecteur->getNbCol(); itligggg++)
            {
                lesParcelles_downdown[itligggg] = Parcelle(ligneCourante[itligggg],itligggg,lignes_traitees);
            }
            //on a traité un ligne donc ligne traitees++
            lignes_traitees++;
            // on lance le calcul de cuvette sur toute les parcelles
            for (i=0; i< lecteur->getNbCol() ; i++)
            {
                calculCuvette(&lesParcelles_up[i]);
            }
            for (i=0; i< lecteur->getNbCol() ; i++)
            {
                calculCuvette(&lesParcelles_center[i]);
            }
            //on retranscrit la première ligne
            for (unsigned int e3 =0 ; e3 < lecteur->getNbCol() ; e3++)
            {
                ecriture[e3] = lesParcelles_up[e3].getNumBassin();
            }
            lecteur->addLine(ecriture);
            jucpt++;
            //on retranscrit la seconde ligne
            for (unsigned int e4 = 0 ; e4 < lecteur->getNbCol() ; e4++)
            {
                ecriture[e4]= lesParcelles_center[e4].getNumBassin();
            }
            lecteur->addLine(ecriture);
            jucpt++;
        }
    }
    //on a fini de charger
    cout<<"bouh1"<<endl;
    for (i=0; i< lecteur->getNbCol() ; i++)
    {
        calculCuvette(&lesParcelles_down[i]);
    }
    for(unsigned int e9 = 0 ; e9 < lecteur->getNbCol(); e9++)
    {
        ecriture[e9]=lesParcelles_down[e9].getNumBassin();
    }
    lecteur->addLine(ecriture);
    for (i=0; i< lecteur->getNbCol() ; i++)
    {
        calculCuvette(&lesParcelles_downdown[i]);
    }
    for(unsigned int e19 = 0 ; e19 < lecteur->getNbCol(); e19++)
    {
        ecriture[e19]=lesParcelles_downdown[e19].getNumBassin();
    }
    lecteur->addLine(ecriture);

    /* ayant fini le fichier
    * on cherche les correspondances pour le deuxième passage
    */
    cout<<"bouh2"<<endl;
    //calculRegroupBassin();
    cout<<"bouh3"<<endl;
// on affiche les bassins
    //afficheLesBassins();
    lecteur->switchVal(MAJBassin);
    cout<<"bouh4"<<endl;
}

/*struct parchaine
{
    Parcelle * parc;
    parchaine * maillon;
};*/

void Terrain::calculCuvette(Parcelle *p)
{
    if(p->getHauteur() != lecteur->getNoValue())
    {

        Parcelle* aux  = p ;
        Parcelle* aux2 = new Parcelle(0,0,0);
        bool fixe = false;
        int compteur = 0;
        //calcul de la cuvette
        //p->affiche();
       /* parchaine * mordek = new parchaine;
        mordek->parc = aux;
        mordek->maillon = NULL;*/

        while (!fixe && aux2->getNumBassin()== -1)
        {
            aux2 = calculCible(aux);
            if (*aux2 == *aux)
            {
                fixe = true;
            }
            /*else
            {

                parchaine * tmp = new parchaine;
                tmp->maillon = mordek;
                tmp->parc = aux2;
                mordek = tmp;
            }*/

           // if(aux->getNumBassin()==-1)
            aux =aux2;
        }


        // CAS OU ON DECOUVRE UN NOUVEAU BASSIN
        if (p->getNumBassin() ==-1 && aux->getNumBassin() ==-1)
        {
            this->setNbBassin(this->getNbBassin()+1);
            // on donne au nouveau puit et a la Parcelle le numbassin
            p->setNumBassin(this->getNbBassin());
            aux->setNumBassin(this->getNbBassin());

            bassin_t b = {aux->getNumBassin(),*aux};
            lesBassins->push_back(b);
            // on ajoute le nouveau puit dnas le vecteur de puit
        }

        //soit la cuvette as un num et pas p
        else if (p->getNumBassin() ==-1 && aux->getNumBassin() != -1)
        {
            p->setNumBassin(aux->getNumBassin());
        }

        // soit la cuvette a un num et la parcelle aussi;
        else if(p->getNumBassin() != -1 && aux->getNumBassin() != -1)
        {
            //pensez que si on a un num, on peut être un bassin
            //si dans les bassins, alors mettre l'ancien num bassin
            for(vector<bassin_t>::iterator it = lesBassins->begin(); it != lesBassins->end(); it++)
            {
                if((*it).puit == *p)
                {

                    MAJBassin[p->getNumBassin()]=aux->getNumBassin();
                }
            }
            p->setNumBassin(aux->getNumBassin());
        }

        //soit cas de case frontiere, p a un num et pas aux
        else if ( p->getNumBassin() != -1 && aux->getNumBassin() == -1)
        {
            aux->setNumBassin(getNbBassin());
            p->setNumBassin(aux->getNumBassin());
            setNbBassin(getNbBassin()+1);
        }
        /*parchaine * tmp;
        while(mordek->maillon != NULL)
        {
            tmp = mordek;
            mordek = mordek->maillon;
            tmp->parc->setNumBassin(p->getNumBassin());
            delete tmp;
        }
        delete mordek;*/
    }
    else
    {
        p->setNumBassin(p->getHauteur());
    }


}

void Terrain::afficheLesBassins()
{
    vector<bassin_t>::iterator it;
    for(it = this->getLesBassins()->begin(); it != this->getLesBassins()->end(); it++)
    {
        cout<<"|"<<(*it).id<<"|"<<(*it).puit.getAbs()<<"|"<<(*it).puit.getOrd()<<endl;
    }
}

void Terrain::calculRegroupBassin()
{
    //on vide la MAJ
    vector<bassin_t>::iterator it;
    vector<bassin_t>::iterator aux;
    for(it=this->getLesBassins()->begin()++; it!=this->getLesBassins()->end(); it++)
    {
        // pour toutes les case du vector lesBassins
        for(aux=this->getLesBassins()->begin(); aux!=it; aux++)
        {
            if((*aux).puit == (*it).puit)
            {
                // ON ENREGISTRE LA MODIF IT SERA REMPLAC2 PAR AUX
                MAJBassin[(*it).id]=(*aux).id;
                // ON SUPPRIME IT DU VECTOR
                it=lesBassins->erase(it);
                //it++;
            }
        }

        //pour chaque case du vector les bassins , on regarde s'il n'as pas une cuvette commune avec ceux d'avant
    }
    // on a regrouper tous les bassins
    //lecteur->switchVal(MAJBassin);
}


